package org.example.backend.utils;

import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import org.apache.tomcat.jni.FileInfo;
import org.imgscalr.Scalr;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 啊昌
 * @date 2025/4/16 18:09
 * MinioUtil 文件操作工具
 */
@Component
public class MinioUtil {

	@Resource
	private MinioClient minioClient;




	/**
	 * 合并视频片段
	 *
	 * @param bucketName       存储桶名称
	 * @param destObjectName   目标对象名称
	 * @param sourceObjectList 源对象列表
	 * @return 合并后的对象写入响应
	 * @throws ServerException           服务器异常
	 */
	public ObjectWriteResponse mergeChunksVideo(String bucketName, String destObjectName, List<ComposeSource> sourceObjectList) throws Exception{
		return // 执行合并操作
				minioClient.composeObject(
						ComposeObjectArgs.builder()
								.bucket(bucketName)
								.object(destObjectName)
								.sources(sourceObjectList)
								.build());
	}
	/**
	 * 创建bucket桶
	 */
	public void createBucket(String bucket) throws Exception {
		boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
		if (!exists) {
			minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
		}
	}

	/**
	 * 上传对象到MinIO
	 *
	 * @param bucketName  存储桶名称
	 * @param objectName  对象名称（包含路径）
	 * @param inputStream 文件输入流
	 * @param size        文件大小
	 * @param contentType 文件类型
	 * @throws MinioException
	 * @throws NoSuchAlgorithmException
	 */
	public void uploadObject(String bucketName, String objectName, InputStream inputStream, long size, String contentType)
			throws Exception{
		try {
			minioClient.putObject(
					PutObjectArgs.builder()
							.bucket(bucketName)
							.object(objectName)
							.stream(inputStream, size, -1) // -1表示分片大小为5MB（默认），也可以自定义
							.contentType(contentType)
							.build());
		} catch (MinioException e) {
			throw new MinioException("上传文件失败: " + e.getMessage());
		}
	}


	/**
	 * 预览图片
	 *
	 * @param fileName 文件名称
	 * @return 文件预览链接
	 */
	public String preview(String fileName, String bucket) throws Exception {
		// 查看文件地址
		GetPresignedObjectUrlArgs build = GetPresignedObjectUrlArgs
				.builder()
				.bucket(bucket)
				.object(fileName).method(Method.GET).build();
		try {
			String url = minioClient.getPresignedObjectUrl(build);
			return url;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}


	/**
	 * 文件上传
	 *
	 * @param file 文件
	 * @return 文件对象名称
	 */
	public String upload(MultipartFile file,String bucket, String objectName) {
		String originalFilename = file.getOriginalFilename();

		System.out.println(originalFilename);

		if (!StringUtils.hasText(originalFilename)) {
			throw new RuntimeException();
		}

		String fileName = UUID.randomUUID() + originalFilename.substring(originalFilename.lastIndexOf("."));
		String prefix = new SimpleDateFormat("yyyy/MM/dd").format(new Date());
		objectName = prefix + "/" + fileName;
		try {
			PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucket).object(objectName)
					.stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
			// 文件名称相同会覆盖
			minioClient.putObject(objectArgs);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		return objectName;
	}


	/**
	 * 上传文件
	 */
	public void uploadFile(InputStream inputStream, String bucket, String objectName) throws Exception {
		minioClient.putObject(PutObjectArgs.builder().bucket(bucket).object(objectName)
				.stream(inputStream, -1, 5242889L).build());
	}

	/**
	 * 列出所有桶
	 */
	public List<String> getAllBucket() throws Exception {
		List<Bucket> buckets = minioClient.listBuckets();
		return buckets.stream().map(Bucket::name).collect(Collectors.toList());
	}

	/**
	 * 列出当前桶及文件
	 */
	public List<FileInfo> getAllFile(String bucket) throws Exception {
		Iterable<Result<Item>> results = minioClient.listObjects(
				ListObjectsArgs.builder().bucket(bucket).build());
		List<FileInfo> fileInfoList = new LinkedList<>();
		for (Result<Item> result : results) {
			FileInfo fileInfo = new FileInfo();
			Item item = result.get();
//			fileInfo.setFileName(item.objectName());
//			fileInfo.setDirectoryFlag(item.isDir());
//			fileInfo.setEtag(item.etag());
			fileInfoList.add(fileInfo);
		}
		return fileInfoList;
	}

	/**
	 * 下载文件
	 */
	public InputStream downLoad(String bucket, String objectName) throws Exception {
		return minioClient.getObject(
				GetObjectArgs.builder().bucket(bucket).object(objectName).build()
		);
	}

	/**
	 * 删除桶
	 */
	public void deleteBucket(String bucket) throws Exception {
		minioClient.removeBucket(
				RemoveBucketArgs.builder().bucket(bucket).build()
		);
	}

	/**
	 * 删除文件
	 */
	public void deleteObject(String bucket, String objectName) throws Exception {
		minioClient.removeObject(
				RemoveObjectArgs.builder().bucket(bucket).object(objectName).build()
		);
	}

	/**
	 * 获取文件url
	 */
//	public String getPreviewFileUrl(String bucketName, String objectName) throws Exception {
//		GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
//				.method(Method.GET)
//				.bucket(bucketName).object(objectName).build();
//		return minioClient.getPresignedObjectUrl(args);
//	}


	/**
	 * 获取文件的预览URL。
	 * <p>
	 * 该方法根据提供的存储桶名称（bucketName）和对象名称（objectName）生成一个预签名的URL，用于预览文件。
	 * 预签名的URL有效期为7天，并且设置了响应头以确保文件在浏览器中直接显示。
	 *
	 * @param bucketName 存储桶的名称
	 * @param objectName 存储桶中的对象名称（即文件名）
	 * @return 返回一个预签名的URL，可用于预览文件
	 * @throws Exception 如果在生成预签名URL过程中发生任何错误，则抛出异常
	 */
	public String getPreviewFileUrl(String bucketName, String objectName) throws Exception {
		// 根据文件名推断 content-type
		String contentType = getContentTypeByExtension(objectName);

		GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder()
				.method(Method.GET)
				.bucket(bucketName)
				.object(objectName)
				.expiry(7, TimeUnit.DAYS)
				.extraQueryParams(Map.of(
						"response-content-disposition", "inline",
						"response-content-type", contentType
				))
				.build();

		return minioClient.getPresignedObjectUrl(args);
	}

	/**
	 * 根据文件扩展名获取MIME类型
	 *
	 * @param filename 文件名
	 * @return 返回对应的MIME类型
	 */
	private String getContentTypeByExtension(String filename) {
		String extension = filename.substring(filename.lastIndexOf('.') + 1).toLowerCase();
		switch (extension) {
			case "jpg":
			case "jpeg":
				return "image/jpeg";
			case "png":
				return "image/png";
			case "gif":
				return "image/gif";
			case "bmp":
				return "image/bmp";
			case "webp":
				return "image/webp";
			case "mp4":
				return "video/mp4";
			case "mov":
				return "video/quicktime";
			case "mp3":
				return "audio/mpeg";
			case "pdf":
				return "application/pdf";
			default:
				return "application/octet-stream";
		}
	}


}
